/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math/vector
// Copyright( c) 2014.  All Rights Reserved
//
// File:		AEVector3f.h
// Author:		Gianluca Belardelli
// Date:		27/01/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEVECTOR3F_H_
#define _AEVECTOR3F_H_

#ifndef _AEMATH_H_
#	error Includere il file core/math/AEMath.h invece di questo.
#endif


// compile time error checking
namespace AECompileError
{
	template <bool b> struct AE_VECTOR3F_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED;
	template <> struct AE_VECTOR3F_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED<true>{ };

	template <bool b> struct AE_VECTOR3F_SUBVECTOR_INDEX_OUT_OF_RANGE;
	template <> struct AE_VECTOR3F_SUBVECTOR_INDEX_OUT_OF_RANGE<true>{ };

	template <bool b> struct AE_VECTOR3F_NOT_IMPLEMENTED_FOR_THIS_VECTOR_LENGTH;
	template <> struct AE_VECTOR3F_NOT_IMPLEMENTED_FOR_THIS_VECTOR_LENGTH<true>{ };

	template <bool b> struct AE_VECTOR3F_UNSUPPORTED_VECTOR_LENGTH;
	template <> struct AE_VECTOR3F_UNSUPPORTED_VECTOR_LENGTH<true>{ };
}

#define AE_VECTOR3F_SUBINDEX_CHECK           AE_COMPILE_TIME_ASSERT( ( I >= 0 ) && ( I < 4 ), AE_VECTOR3F_SUBVECTOR_INDEX_OUT_OF_RANGE)
#define AE_VECTOR3F_NOT_IMPLEMENTED          AE_COMPILE_TIME_ASSERT( N == 0, AE_VECTOR3F_NOT_IMPLEMENTED_FOR_THIS_VECTOR_LENGTH)
#define AE_VECTOR3F_UNSUPPORTED_LENGTH_CHECK AE_COMPILE_TIME_ASSERT( ( N > 0 ) && ( N <= 4 ), AE_VECTOR3F_UNSUPPORTED_VECTOR_LENGTH)
#define AE_VECTOR3F_TEMPLATE_CONFIG_NOT_IMPLEMENTED AE_COMPILE_TIME_ASSERT( A < 0, AE_VECTOR3F_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED)

/// \brief
/// La classe rappresenta un vettore a quattro componenti e contiene quattro numeri in virgola mobile a seconda della
/// definizione di AEFLOAT32. Ci sono implementazioni SIMD ottimizzate disponibili per diverse piattaforme.
/// Esse utilizzano strutture dati specifiche della piattaforma. Cos&igrave;, rendere la classe portabile, nulla deve essere assunto
/// per quanto concerne la disposizione interna dei quattro numeri in virgola mobile .
/// Sono stati implementati metodi template per l'accesso ottimizzato alle componenti del vettore.
/// E' consigliabile utilizzare tali metodi quando si conosce a priori l'elemento da utilizzare. Negli
/// altri casi si pu&ograve; utilizzare il rispettivo metodo non template.
/// Per accedere ai contenuti di un vettore, &egrave; raccomandato l'utilizzo dei metodi Get/SetComponent i quali,
/// operando con valori di tipo AESimdFloat32, che a loro volta hanno metodi efficienti per l'esecuzione 
/// di operazioni aritmetiche e non, evitano di uscire fuori dalla pipeline di elaborazione SIMD.
/// La precisione a 23bit &egrave; quasi come la versione float IEEE, ma aumenta sostanzialmente la velocit&agrave;
/// di esecuzione a discapito della precisione di calcolo. La precisione a 12bit offre un esecuzione ancora
/// pi&ugrave; veloce ma una precisione nettamente inferiore. E' consigliabile utilizzare la classe partendo da una
/// precisione Full per poi eventualmente abbassarla a seconda del risultato richiesto. 
class AEVector3f
{
// Members
public:
	/// \brief
	/// Membro pubblico contenente i quattro valori float
	/// che rappresentano le componenti X, Y, Z e W del
	/// vettore. Il valore W non viene utilizzato.
	AE_ALIGN16 AEQuadFloat32 m_qfVector;

// Methods
public:
	AE_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( TOBEDFINED, AEVector3f );
	
	/** @name Costruttori */
	/// @{
	///////////////////////////////////////////////////////////////
	/// \brief
	/// Costruttore. Non inizializza il vettore.
	AE_FORCEINLINE AEVector3f( void ) { };

	/// \brief
	/// Costruttore. Inizializza tutte le componenti del vettore con lo
	/// stesso valore.
	/// \param qfValue
	/// Valore assegnato alle componenti.
	// SSE FPU
	AE_FORCEINLINE explicit AEVector3f( const AEQuadFloat32 &qfValue );

	/// \brief
	/// Costruttore. Inizializza individualmente ogni componente.
	/// \param fX Valore della componente X.
	/// \param fY Valore della componente Y.
	/// \param fZ Valore della componente Z.
	/// \param fW Valore della componente W. Per default &egrave; 0.
	// SSE FPU
	AE_FORCEINLINE AEVector3f( AEFLOAT32 fX, AEFLOAT32 fY, AEFLOAT32 fZ );

	/// Costruttore di copia.
	/// \param vcCopy Referenza all'oggetto da copiare.
	// SSE FPU
	AE_FORCEINLINE AEVector3f( const AEVector3f &vcCopy );
	
	/// @}
	/** @name Funzioni statiche */
	/// @{
	/// \brief
	///   Returns a zero vector.
	//AE_FORCEINLINE static const AEVector3f ZeroVector( void ) { return AEVector3f( AEQuadFloat32( 0.0f ) ); }

	/// @}
	/** @name Conversioni */
	/// @{

	/// \brief
	///   Returns a AEVector2 with the same values for x and y.
	AE_FORCEINLINE const AEVector2 GetAsVec2( void ) const;

	/// @}
	/** @name Inizializzazione base */
	/// @{
	/// \brief
	/// Imposta tutte le componenti del vettore a 0.0.
	AE_FORCEINLINE void SetZero( void );

	/// \brief Imposta le componenti del vettore con i valori dati.
	/// \param fX Componente X.
	/// \param fY Componente Y.
	/// \param fZ Componente Z.
	/// \param fW Componente W.
	AE_FORCEINLINE void Set( AESimdFloat32ConstRef fX, AESimdFloat32ConstRef fY, AESimdFloat32ConstRef fZ );

	/// \brief Imposta le componenti del vettore con i valori dati.
	/// \param fX Componente X.
	/// \param fY Componente Y.
	/// \param fZ Componente Z.
	/// \param fW Componente W.
	AE_FORCEINLINE void Set( AEFLOAT32 fX, AEFLOAT32 fY, AEFLOAT32 fZ );

	/// \brief Imposta tutte le componenti del vettore con il valore dato.
	/// \param fValue Valore da impostare.
	AE_FORCEINLINE void SetAll( const AEFLOAT32 &fValue );

	/// \brief Imposta tutte le componenti del vettore con il valore dato.
	/// \param fValue Valore da impostare.
	AE_FORCEINLINE void SetAll( AESimdFloat32ConstRef fValue );

	/// \brief Imposta la componente specificata dal parametro template I a zero.
	/// \param I Componente da azzerare.
	/// \remark E' preferibile utilizzare questo metodo quando l'indice della
	/// componente &egrave; conosciuto durante la compilazione.
	template <int I> AE_FORCEINLINE void ZeroComponent( void );

	/// \brief Imposta la componente specificata da nIndex a 0.
	/// \remark Utilizzare questo metodo solo se l'indice della componente
	/// non &egrave; conosciuto durante la compilazione.
	AE_FORCEINLINE void ZeroComponent( const AEINT32 nIndex );

	/// @}
	/** @name Metodi di calcolo */
	/// @{
	/// \brief Addiziona a questo vettore il vettore passato nel parametro
	/// ( this += vcVector )
	/// \param vcVector Vettore da addizionare.
	AE_FORCEINLINE void Add( AEVector4fRefParam vcVector );

	/// \brief Sottrae a questo vettore il vettore passato nel parametro
	/// ( this -= vcVector )
	/// \param vcVector Vettore da sottrarre.
	AE_FORCEINLINE void Sub( AEVector4fRefParam vcVector );

	/// \brief Moltiplica questo vettore con il vettore passato nel parametro.
	/// ( this *= vcVector )
	/// \param vcVector Vettore da moltiplicare.
	AE_FORCEINLINE void Mul( AEVector4fRefParam vcVector );

	/// \brief Moltiplica ogni componente di questo vettore con il
	/// valore fValue. ( this *= fValue )
	/// \param fValue Valore da moltiplicare.
	/// INL
	AE_FORCEINLINE void Mul( AESimdFloat32ConstRef fValue );

	/// \brief Divide questo vettore con il vettore passato nel parametro.
	/// ( this /= vcVector )
	/// \param vcVector Vettore da moltiplicare.
	/// \remark Precisione di default a 23bit, la divisione
	/// per 0 non viene controllata.
	AE_FORCEINLINE void Div( AEVector4fRefParam vcVector );

	/// @}
	/** @name Inizializzazione avanzata */
	/// @{
	/// \brief
	/// Imposta questo vettore con la somma dei due vettori
	/// passati nel parametro ( this = vcVector1 + vcVector2 )
	/// \param vcVector1 Primo vettore da addizionare.
	/// \param vcVector2 Secondo vettore da addizionare.
	AE_FORCEINLINE void SetAdd( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief Imposta questo vettore con la differenza tra i due vettori
	/// passati nel parametro ( this = vcVector1 - vcVector2 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	AE_FORCEINLINE void SetSub( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief Imposta questo vettore con il prodotto tra i due vettori
	/// passati nel parametro ( this = vcVector1 * vcVector2 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	AE_FORCEINLINE void SetMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief Imposta questo vettore con il prodotto tra il valore fValue
	/// e il vettore passati nel parametro ( this = fValue * vcVector )
	/// \param fValue Valore float.
	/// \param vcVector Vettore.
	AE_FORCEINLINE void SetMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector );

	/// \brief Imposta questo vettore con il prodotto tra il valore fValue
	/// e il vettore passati nel parametro ( this = fValue * vcVector )
	/// \param vcVector Vettore.
	/// \param fValue Valore float.
	AE_FORCEINLINE void SetMul( AEVector4fRefParam vcVector, AESimdFloat32ConstRef fValue );
	
	/// \brief Imposta questo vettore con la differenza tra il vettore vcVector1
	/// e il prodotto di vcVector2 moltiplicato per fValue.
	/// ( this = vcVector1 - vcVector2*fValue )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	/// \param fValue Valore float.
	AE_FORCEINLINE void SetSubMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2, AESimdFloat32ConstRef fValue );
	
	/// \brief Imposta questo vettore con la differenza tra il vettore vcVector1
	/// e il prodotto di vcVector2 moltiplicato per vcVector3.
	/// ( this = vcVector1 - vcVector2*vcVector3 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	/// \param vcVector3 Terzo vettore.
	AE_FORCEINLINE void SetSubMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2, AEVector4fRefParam vcVector3 );

	/// \brief Imposta questo vettore con la somma tra il vettore vcVector1
	/// e il prodotto di vcVector2 moltiplicato per fValue.
	/// ( this = vcVector1 + vcVector2*fValue )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector1 Secondo vettore.
	/// \param fValue Valore float.
	AE_FORCEINLINE void SetAddMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2, AESimdFloat32ConstRef fValue );

	/// \brief Imposta questo vettore con la somma tra il vettore vcVector1
	/// e il prodotto di vcVector2 moltiplicato per vcVector3.
	/// ( this = vcVector1 + vcVector2*vcVector3 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	/// \param vcVector3 Terzo vettore.
	AE_FORCEINLINE void SetAddMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2, AEVector4fRefParam vcVector3 );

	/// \brief Addizziona a questo vettore il prodotto tra vcVector e fValue
	/// ( this += vcVector*fValue )
	/// \param vcVector Vettore.
	/// \param fValue Valore float.
	AE_FORCEINLINE void AddMul( AEVector4fRefParam vcVector, AESimdFloat32ConstRef fValue );

	/// \brief Addizziona a questo vettore il prodotto tra vcVector e fValue
	/// ( this += fValue*vcVector )
	/// \param fValue Valore float.
	/// \param vcVector Vettore.
	AE_FORCEINLINE void AddMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector );

	/// \brief Addizziona a questo vettore il prodotto tra vcVector1 e vcVector2.
	/// ( this += vcVector1*vcVector2 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	AE_FORCEINLINE void AddMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief Sottrae a questo vettore il prodotto tra vcVector e fValue
	/// ( this -= vcVector*fValue )
	/// \param vcVector Vettore.
	/// \param fValue Valore float.
	AE_FORCEINLINE void SubMul( AEVector4fRefParam vcVector, AESimdFloat32ConstRef fValue );

	/// \brief Sottrae a questo vettore il prodotto tra vcVector1 e vcVector2.
	/// ( this -= vcVector1*vcVector2 )
	/// \param vcVector1 Primo vettore.
	/// \param vcVector2 Secondo vettore.
	AE_FORCEINLINE void SubMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief Sottrae a questo vettore il prodotto tra vcVector e fValue
	/// ( this -= fValue*vcVector )
	/// \param fValue Valore float.
	/// \param vcVector Vettore.
	AE_FORCEINLINE void SubMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector );

	/// \brief Imposta questo vettore con il risultato del prodotto cross tra vcVector1 e vcVector2
	/// ( this = vcVector1 cross vcVector2 )
	/// \param vcVector1 Vettore.
	/// \param vcVector2 Vettore.
	AE_FORCEINLINE void SetCross( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	// INL
	template <int N> AE_FORCEINLINE void SetHorizontalAdd( AEVector4fRefParam vcVector );
	
	/// \brief Esegue la somma delle N componenti selezionate. ( return x+y+z+w )
	/// \return Valore float della somma.
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetHorizontalAdd( void ) const;

	/// \brief Esegue il prodotto delle N componenti selezionate. ( return x*y*z*w )
	/// \return Valore float del prodotto.
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetHorizontalMul( void ) const;

	// INL
	template <int N> AE_FORCEINLINE void SetHorizontalMax( AEVector4fRefParam vcVector );
	
	/// \brief Ritorna il valore massimo presente nelle componenti del vettore
	/// ( return max(x,y,z,w)
	/// \return Valore float della componente maggiore.
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetHorizontalMax( void ) const;
	
	// INL
	template <int N> AE_FORCEINLINE void SetHorizontalMin( AEVector4fRefParam vcVector );

	/// \brief Ritorna il valore minimo presente nelle componenti del vettore
	/// ( return min(x,y,z,w)
	/// \return Valore float della componente pi&ugrave; piccola.
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetHorizontalMin( void ) const;

	/// \brief Imposta questo vettore con il reciproco del vettore passato nel parametro.
	/// ( this = 1/vcVector )
	/// \param vcVector Vettore sul quale calcolare il reciproco.
	/// \remark Precisione di default a 23bit, la divisione
	/// per 0 non viene controllata.
	AE_FORCEINLINE void SetReciprocal( AEVector4fRefParam vcVector );

	/// \brief Imposta questo vettore con il reciproco del vettore passato nel parametro.
	/// ( this = 1/vcVector )
	/// \param vcVector Vettore sul quale calcolare il reciproco.
	/// \remark Precisione impostata tramite il parametro template AEMathAccuracyMode,
	/// divisione per 0 controllata tramite il parametro template AEMathDivByZeroMode.
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void SetReciprocal( AEVector4fRefParam vcVector );

	/// \brief Imposta questo vettore con la radice quadrate del vettore passato nel parametro.
	/// ( this = sqrt(vcVector) )
	/// \param vcVector Vettore sul quale calcolare la radice quadrata.
	/// \remark Precisione di default a 23bit, valore negativo per la
	/// radice quadrata controllati e impostati a zero?????
	/// SSE FPU
	AE_FORCEINLINE void SetSqrt( AEVector4fRefParam vcVector );

	/// \brief Imposta questo vettore con la radice quadrate del vettore passato nel parametro.
	/// ( this = sqrt(vcVector) )
	/// \param vcVector Vettore sul quale calcolare la radice quadrata.
	/// \remark Precisione impostata tramite il parametro template AEMathAccuracyMode,
	/// valori negativi per la radice quadrata controllati tramite il parametro template AEMathNegSqrtMode.
	/// SSE FPU
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE void SetSqrt( AEVector4fRefParam vcVector );

	/// \brief Set self component-wise to one over square root of \a a. ( self = 1/sqrt(a) ).
	/// Accuracy: 23 bit, negative values of \a a checked and set to zero, divide-by-0 checked and set to zero
	// SSE FPU
	AE_FORCEINLINE void SetSqrtInverse( AEVector4fRefParam vcVector );

	// SSE FPU
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE void SetSqrtInverse( AEVector4fRefParam vcVector );

	/// Store \a v with self while flipping the signs of the first N components. ( self = N ? -v : v )
	// SSE
	template <int N> AE_FORCEINLINE void SetNeg( AEVector4fRefParam vcVector );

	/// Returns the dot product of self with \a a represented by N components. ( return self dot a )
	// SSE FPU
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetDot( AEVector4fRefParam vcVector ) const;

	// SSE FPU
	AE_FORCEINLINE const AESimdFloat32 Dot4xyz1( AEVector4fRefParam vcVector ) const;
	
	/// Sets all components of self to the N component dot product of \a a and \a b. ( self = a dot b )
	/// INL
	template <int N> AE_FORCEINLINE void SetDot( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// Set self to the component-wise quotient of \a a over \a b. ( self = a/b ).
	/// See the documentation at the template values for the requested behavior.
	/// SSE FPU
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void SetDiv( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// SSE	FPU
	AE_FORCEINLINE void SetDiv( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// Component-wise division by \a a. ( self /= a ).
	/// See the documentation at the template values for the requested behavior.
	/// SSE FPU
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void Div( AEVector4fRefParam vcVector );
	
	/// Returns the length of the vector represented by N of its components. ( return sqrt(self dot self) ).
	/// Accuracy: 23 bit, negative values checked and set to zero
	// INL
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetLength( void ) const;
	
	/// Returns the length of the vector represented by N of its components. ( return sqrt(self dot self) ).
	/// See the documentation at the template values for the requested behavior.
	// INL
	template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 GetLength( void ) const;

	/// Returns the squared length of the vector represented by N of its components. ( return (self dot self) )
	// INL
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetLengthSquared( void ) const;
	
	/// Returns the inverse length of the vector represented by N of its components. ( return 1 / sqrt(self dot self) ).
	/// Accuracy: 23 bit, negative sqrt values checked and set to zero, divide-by-0 checked and set to zero
	// INL
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetLengthInverse( void ) const;

	/// Returns the inverse length of the vector represented by N of its components. ( return 1 / sqrt(self dot self) ).
	/// See the documentation at the template values for the requested behavior.
	// INL
	template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 GetLengthInverse( void ) const;
	
	/// Normalizes self as an N-component vector. Unused components in self are undefined afterwards. ( self = |self| ).
	/// Accuracy: 23 bit, negative sqrt values checked and set to zero, divide-by-0 checked and set to zero
	// INL
	template <int N> AE_FORCEINLINE void Normalize( void );

	/// Normalizes self as an N-component vector. Unused components in self are undefined afterwards. ( self = |self| ).
	/// See the documentation at the template values for the requested behavior.
	// INL
	template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE void Normalize( void );
	
	/// Normalizes self as an N-component vector and returns the length of self before normalization. Unused components in self are undefined afterwards. ( return self = |self| ).
	/// Accuracy: 23 bit, negative sqrt values checked and set to zero, divide-by-0 checked and set to zero
	// INL
	template <int N> AE_FORCEINLINE const AESimdFloat32 GetLengthAndNormalize( void );

	/// Normalizes self as an N-component vector and returns the length of self before normalization. Unused components in self are undefined afterwards. ( return self = |self| ).
	/// See the documentation at the template values for the requested behavior.
	// INL
	template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 GetLengthAndNormalize( void );

	/// Returns the Euclidean distance between self as a point and the point \a p. ( return len(self - p) ).
	/// Accuracy: 23 bit, negative sqrt values checked and set to zero, divide-by-0 checked and set to zero
	// INL
	AE_FORCEINLINE const AESimdFloat32 GetDistanceTo( AEVector4fRefParam vcVector ) const;

	/// Returns the Euclidean distance between self as a point and the point \a p. ( return len(self - p) ).
	/// See the documentation at the template values for the requested behavior.
	// INL
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 GetDistanceTo( AEVector4fRefParam vcVector ) const;

	/// Returns the squared Euclidean distance between self as a point and the point \a p. ( return len*len(self - p) )
	// INL
	AE_FORCEINLINE const AESimdFloat32 GetDistanceToSquared( AEVector4fRefParam vcVector ) const;

	/// Set the w component of self to the negative 3-component dot product of \a aPointOnPlane with self. The xyz components of self are unchanged.
	/// ( self.w = -p.dot<3>(self) )
	// INL
	AE_FORCEINLINE void SetPlaneConstant( AEVector4fRefParam vcPointOnPlane );

	/// @}
	/** @name Accesso separato alle componenti XYZ */
	/// @{
	/// \brief Imposta le componenti X, Y e Z di questo vettore con il valore delle
	/// componenti XYZ del vettore vcXYZVector. La componente W rimane invariata.
	/// \param vcXYZVector Vettore xyz.
	AE_FORCEINLINE void SetXYZ( AEVector4fRefParam vcXYZVector );

	/// \brief Imposta le componenti X, Y e Z di questo vettore con il valore fValue.
	/// La componente W rimane invariata.
	/// \param fValue Valore da attribuire alle componenti X, Y e Z
	AE_FORCEINLINE void SetXYZ( AEFLOAT32 fValue );

	/// \brief Imposta le componenti X, Y e Z di questo vettore con il valore fValue.
	/// La componente W rimane invariata.
	/// \param fValue Valore da attribuire alle componenti X, Y e Z
	AE_FORCEINLINE void SetXYZ( AESimdFloat32ConstRef fValue );

	/// Add the xyz components of \a v to the xyz components of self. The w component of self is undefined afterwards.
	// SSE
	AE_FORCEINLINE void AddXYZ( AEVector4fRefParam vcXYZVector );

	/// Subtract the xyz components of \a v from the xyz components of self. The w component of self is undefined afterwards.
	// SSE
	AE_FORCEINLINE void SubXYZ( AEVector4fRefParam vcXYZVector );

	/// Sets value of component I.  (0,1,2,3) correspond to the (x,y,z,w) components respectively.
	// SSE FPU
	template <int I> AE_FORCEINLINE void SetComponent( AESimdFloat32ConstRef fValue );

	/// Sets value of component \a i.  (0,1,2,3) correspond to the (x,y,z,w) components respectively.
	/// \remark Use this method only when the component index is not a compile time constant.
	// SSE FPU
	AE_FORCEINLINE void SetComponent( const AEINT32 nIndex, AESimdFloat32ConstRef fValue );

	///////////////////////////////////////////////////////////////
	/// @}
	/** @name Controlli di comparazione per valore */
	/// @{
	///////////////////////////////////////////////////////////////
	/// Component-wise compare self less than \a a. ( self < a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpL( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self less than or equal to \a a. ( self <= a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpLE( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self greater than \a a. ( self > a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpG( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self greater than or equal \a a. ( self >= a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpGE( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self equal to \a a. ( self == a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpE( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self not equal to \a a. ( self != a )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison CmpNE( AEVector4fRefParam vcVector ) const;

	/// Component-wise compare self less than zero. ( self < 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison LessZero( void ) const;

	/// Component-wise compare self less than or equal zero. ( self <= 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison LessEqualZero( void ) const;

	/// Component-wise compare self greater than zero. ( self > 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison GreaterZero( void ) const;

	/// Component-wise compare self greater than or equal zero. ( self >= 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison GreaterEqualZero( void ) const;

	/// Component-wise compare self equal to zero. ( self == 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison EqualZero( void ) const;

	/// Component-wise compare self not equal to zero. ( self != 0 )
	// SSE FPU
	AE_FORCEINLINE const AEVector4fComparison NotEqualZero( void ) const;

	/// Component-wise sign test whether negative sign is set, in which case the corresponding flag in the returned mask is set to true. ( self <= -0 ).
	/// This includes detecting floating point -0.0 which also returns true. Use the compare methods to perform arithmetic
	/// compares on the floating point value.
	// SSE
	AE_FORCEINLINE const AEVector4fComparison SignBitSet( void ) const;

	/// Component-wise sign test whether negative sign is clear, in which case the corresponding flag in the returned mask is set to true. ( self >= +0 ).
	/// This includes detecting floating point +0.0 which also returns true. Use the compare methods to perform arithmetic
	/// compares on the floating point value.
	// SSE
	AE_FORCEINLINE const AEVector4fComparison SignBitClear( void ) const;


	///////////////////////////////////////////////////////////////
	/// @}
	/** @name Controlli di validit&agrave; */
	/// @{
	///////////////////////////////////////////////////////////////

	/// Returns true if the first N components are valid finite floating point numbers.
	/// SSE FPU
	template <int N> AE_FORCEINLINE AEBOOL32 IsOk( void ) const;

	/// \brief
	///   Checks whether all components are zero within some epsilon range.
	AE_FORCEINLINE bool IsZero( float fEpsilon = AEMATH_DEFAULT_EPSILON ) const;

	/// \brief
	///   Checks whether this vector and rhs are exactly equal.
	AE_FORCEINLINE bool IsIdentical( const AEVector3f &vcRhs ) const;

	/// \brief
	///   Checks whether this vector and rhs are equal within some epsilon range.
	AE_FORCEINLINE bool IsEqual( const AEVector3f &vcRhs,  float fEpsilon ) const;

	/// \brief
	///   Checks whether this vector has a length of 1, within some epsilon range.
	///
	/// \param fEpsilon
	///   The maximum deviation that is allowed. The default value is reasonably large to handle the most common cases.
	///
	/// \sa AEMath::isFloatEqual
	AE_FORCEINLINE bool IsNormalized( float fEpsilon = AEMATH_DEFAULT_EPSILON ) const;

	///////////////////////////////////////////////////////////////
	/// @}
	/** @name Operazioni di Load e Store */
	/// @{
	///////////////////////////////////////////////////////////////
	/// Carica nel vettore N componenti da un puntatore AEDOUBLE64. Le componenti non caricate
	/// assumono un valore indefinito. Il puntatore lpAddr deve essere allineato per le
	/// operazioni SIMD.
	/// \param lpAddr Puntatore ad un indirizzo AEDOUBLE64.
	// SSE FPU
	template <int N> AE_FORCEINLINE void Load( const AEDOUBLE64 *lpAddr );

	/// Carica nel vettore N componenti da un puntatore AEFLOAT32. Le componenti non caricate
	/// assumono un valore indefinito. Il puntatore lpAddr deve essere allineato per le
	/// operazioni SIMD.
	/// \param lpAddr Puntatore ad un indirizzo AEFLOAT32.
	// SSE FPU
	template <int N> AE_FORCEINLINE void Load( const AEFLOAT32 *lpAddr );

	/// Carica nel vettore N componenti da un puntatore AEDOUBLE64. Le componenti non caricate
	/// assumono un valore indefinito. L'allineamento del puntatore lpAddr &egrave; impostato
	/// tramite il parametro template AEMathIoMode.
	/// \param lpAddr Puntatore ad un indirizzo AEDOUBLE64.
	// SSE FPU
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Load( const AEDOUBLE64 *lpAddr );

	/// Carica nel vettore N componenti da un puntatore AEFLOAT32. Le componenti non caricate
	/// assumono un valore indefinito. L'allineamento del puntatore lpAddr &egrave; gestito
	/// tramite il parametro template AEMathIoMode.
	/// \param lpAddr Puntatore ad un indirizzo AEFLOAT32.
	// SSE FPU
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Load( const AEFLOAT32 *lpAddr );

	/// Salva nell'indirizzo lpAddr N componenti del vettore, utilizzando
	/// l'arrotondamento di default del sistema.
	/// Il puntatore lpAddr deve essere allineato per le operazioni SIMD.
	/// \param lpAddr Puntatore ad un indirizzo AEDOUBLE64.
	// SSE FPU
	template <int N> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// Salva nell'indirizzo lpAddr N componenti del vettore, utilizzando
	/// l'arrotondamento di default del sistema.
	/// Il puntatore lpAddr deve essere allineato per le operazioni SIMD.
	/// \param lpAddr Puntatore ad un indirizzo AEFLOAT32.
	// SSE FPU
	template <int N> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;

	/// Store double precision floating point values of N components to linear addresses at \a p.
	/// See the documentation at the template values for the requested IO mode.
	/// \param lpAddr Puntatore ad un indirizzo AEDOUBLE64.
	// SSE FPU
	template <int N, AEMathIoMode A, AEMathRoundingMode R> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// Store single precision floating point values of N components to linear addresses at \a p.
	/// See the documentation at the template values for the requested IO mode.
	/// \param lpAddr Puntatore ad un indirizzo AEFLOAT32.
	// SSE FPU
	template <int N, AEMathIoMode A, AEMathRoundingMode R> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;

	/// Store double precision floating point values of N components to linear addresses at \a p.
	/// The rounding is the system default.
	/// See the documentation at the template values for the requested IO mode.
	/// \param lpAddr Puntatore ad un indirizzo AEDOUBLE64.
	// SSE FPU
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// Store single precision floating point values of N components to linear addresses at \a p.
	/// The rounding is the system default.
	/// See the documentation at the template values for the requested IO mode.
	/// \param lpAddr Puntatore ad un indirizzo AEFLOAT32.
	// SSE FPU
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;
		
	/// @}
	/** @name Operatori */
	/// @{

	/// Sets all components from \a v. This operator is register aliasing safe. ( self = v )
	// INL
	AE_FORCEINLINE void operator= ( AEVector4fRefParam vcVector );

	/// Gives read/write access to element i.  (0,1,2,3) correspond to the (x,y,z,w) components respectively.
	/// \remark Use this method only for storage purposes or immediate manipulation when the component index is not a compile time constant.
	// SSE FPU
	AE_FORCEINLINE AEFLOAT32 &operator() ( AEINT32 nIndex );

	/// Gives read only access to element i.  (0,1,2,3) correspond to the (x,y,z,w) components respectively.
	/// \remark Use this method only for storage purposes when the component index is not a compile time constant.
	// SSE FPU
	AE_FORCEINLINE const AEFLOAT32 &operator() ( AEINT32 nIndex ) const;

	/// @}
	/** @name Accesso componenti */
	/// @{
	/// \brief Ritorna la componente I-esima del vettore.
	/// 0, 1, 2, 3 corrispondono rispettivamente a X, Y, Z, W.
	/// \note La componente W non &egrave; utilizzata e pu&ograve; contenere valori non attesi.
	// SSE FPU
	template <int I> AE_FORCEINLINE const AESimdFloat32 GetComponent( void ) const;

	/// Return component \a i.  (0,1,2,3) correspond to the (x,y,z,w) components respectively.
	/// \remark Use this method only when the component index is not a compile time constant.
	// SSE FPU
	AE_FORCEINLINE const AESimdFloat32 GetComponent( const AEINT32 nIndex ) const;

	/// \brief Ritorna la componente X del vettore.
	AE_FORCEINLINE const AESimdFloat32 GetX( void ) const;

	/// \brief Ritorna la componente Y del vettore.
	AE_FORCEINLINE const AESimdFloat32 GetY( void ) const;
	
	/// \brief Ritorna la componente Z del vettore.
	AE_FORCEINLINE const AESimdFloat32 GetZ( void ) const;

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Lunghezza e distanza
	/// @{
	///////////////////////////////////////////////////////////////

	// SSE
	AE_FORCEINLINE void SetFlipSign( AEVector4fRefParam vcVector, AEVector4fRefParam vSign );

	/// Component-wise copy values from \a v while flipping the sign of each value if the scalar value of \a sSign is negative. ( self = (sSign < 0) ? -v : v )
	// SSE
	AE_FORCEINLINE void SetFlipSign( AEVector4fRefParam vcVector, AESimdFloat32ConstRef sSign );


	/// \brief
	///   Normalizes the vector, if its length is non-zero. Otherwise the vector will stay unmodified.
	///
	/// If normalization was not possible, it returns HKV_FAILURE otherwise HKV_SUCCESS.
	/// In case of failure the vector will not be modified. That means the vector will either be all zero
	///( and thus zero-length) or some component is invalid( +/-Infinity or NaN).
	///
	/// \param fEpsilon If all values are in range [-fEpsilon; +fEpsilon] the vector is considered to be 'zero'.
	///
	/// \sa AEVector3f::Normalize
	/// \sa AEVector3f::NormalizedEnsureUnitLength
	AE_FORCEINLINE AERESULT NormalizeIfNotZero( float fEpsilon = AEMATH_SMALL_EPSILON );

	/// \brief
	///   Normalizes this vector under all circumstances and returns its previous length.
	///
	/// If the vector can not be normalized, its x component will be set to 1 and all other components to 0.
	/// In this case the function will return 0, as the vectors previous length was 0( or invalid).
	/// If the vector can be normalized, the previous length is returned.
	///
	/// \sa AEVector3f::Normalize
	/// \sa AEVector3f::NormalizeIfNotZero
	AE_FORCEINLINE float NormalizedEnsureUnitLength( void );



	/// \brief
	///   Normalizes this vector and then multiplies it by f.
	///
	/// Returns HKV_FAILURE, if the vector could not be normalized.
	/// In this case the vector does not change.
	/// In case of failure the function acts identical to normalizeIfNotZero.
	///
	/// \param f
	///   The length to which to set the vector.
	/// \param fEpsilon
	///   If the vector's original length is below this threshold normalization fails and thus the vector's length is not changed.
	///
	/// \sa AEVector3f::NormalizeIfNotZero
	AE_FORCEINLINE AERESULT SetLength( float fValue, float fEpsilon = AEMATH_SMALL_EPSILON );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Modifica delle componenti
	/// @{
	///////////////////////////////////////////////////////////////

	/// \brief
	///   Negates this vector, e.g. flips the sign of each component.
	AE_FORCEINLINE void Negate( void );


	/// \brief
	///   Each component of this vector is set to the maximum of itself and the corresponding component of rhs.
	AE_FORCEINLINE void SetMax( const AEVector3f &vcRhs );

	/// \brief
	///   Each component of this vector clamped to the min/max range defined by vcMinVal and vcMaxVal.
	AE_FORCEINLINE void ClampTo( const AEVector3f &vcMinVal, const AEVector3f &vcMaxVal );

	/// \brief
	///   Each component of this vector is set to the minimum of lhs and the corresponding component of rhs.
	/// SSE
	AE_FORCEINLINE void SetMin( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief
	///   Each component of this vector is set to the maximum of lhs and the corresponding component of rhs.
	AE_FORCEINLINE void SetMax( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 );

	/// \brief
	///   Each component of this vector is set to val clamped to the min/max range defined by vcMinVal and vcMaxVal.
	AE_FORCEINLINE void SetClamped( const AEVector3f &vcVal, const AEVector3f &vcMinVal, const AEVector3f &vcMaxVal );

	/// \brief
	///   All components of this vector are set to the absolute value of the corresponding component of val.
	/// SSE
	AE_FORCEINLINE void SetAbs( AEVector4fRefParam vcVector );


	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Funzioni di utilit&agrave;
	/// @{
	///////////////////////////////////////////////////////////////

	/// \brief
	///   Sets this vector to the linear interpolation of lhs and rhs using t as the interpolation factor.
	AE_FORCEINLINE void SetInterpolate( const AEVector3f &vcLhs, const AEVector3f &vcRhs, float fFactor );

	/// @}


};

#endif // _AEVECTOR3F_H_

